/*
 * Copyright (C) 2011 Project R'yleh Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.Arkham;

import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11ExtensionPack;

import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;



public class RendererCore  implements Renderer 
{
	public final MeshManager root;
	//private final TextureManager TexRoot;
	private Timer timer;
	private float moveX = 0.0f;
	private float moveY = 0.0f;

	private float[] mPosition = { 0.0f, 3.0f, 8.0f};
	private float[] mRotation = { 0.0f, 0.0f, 0.0f};
	TextView mText;
   
	private boolean mIsSoftwareRender = false;
	private boolean mIsOGL10 = false;
	private boolean mSupportTexture = false;
	private boolean mSupportVBO = false;

	
	private float[] CameraFocus = { 0.0f, 0.0f, 0.0f};
	
	private float [] cameraUpVector = { 0.0f, 1.0f, 0.0f};
	
	private boolean isDirty = false;
	
	private short mTickCount =0;
	
	private static final String TAG = RendererCore.class.getSimpleName();
	protected Context context;
	protected GL10 mGL;
	protected View mView;
	protected int mHeight, Width;
	private int orbitIndex = 0;
	private float cameraRadius = 8.0f;

	protected boolean orbitActivated = false;
	public int activeIndex;
	
	private float pointCoefX[] = {0.0f, -0.866f,  -0.866f , 0.0f, -0.866f,  -0.866f};
	private float pointCoefZ[] = {1.0f, 0.5f,  -0.5f , -1.0f, -0.5f,  0.5f};
	
	float ProjectionView[] = new float[16];
	int[] Viewport = new int[4];
	
	public RendererCore(Context cont)
	{
		
		MeshManager Manager = new MeshManager();
		//mText = tv;
		root = Manager;
		
		context = cont;
	}
	
	public void onDrawFrame(GL10 gl)
	{
		//updatePosition(0.0f, 0.0f, move);
		//Log.i(TAG,"Time Elapsed " + timer.getElapsed());
		
		
			
		
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | 
				   GL10.GL_DEPTH_BUFFER_BIT);
		
		gl.glClearDepthx(65536);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		
		gl.glLoadIdentity();
		GLU.gluLookAt(gl, mPosition[0], mPosition[1], mPosition[2], CameraFocus[0], CameraFocus[1], CameraFocus[2], cameraUpVector[0], cameraUpVector[1], cameraUpVector[2]);
		
		
		root.tickCount = mTickCount;
		root.OnDraw(gl);
		gl.glFlush();
		
		
		//updateRotation(1.0f, 1.0f, 0.0f);
		mTickCount++;
		
		
		mText.post(
				new Runnable()
		{

			public void run()
			{ 
				if(timer.getElapsed() > 1000)
				{
				mText.setText("Arkham Academy FPS: " +  mTickCount );
				timer.resetTimer();
				mTickCount =0;
				//Log.i(TAG, "Mesh list Size:" + root.size());
				
				
				}
				
			}
			
		});
//		      while(main.timer.getElapsed() < 33)
//		      {
//		    	 try {
//					this.wait(1);
//				} catch (InterruptedException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
//		      }
		     
		      
	
		}

	public void onSurfaceChanged(GL10 gl, int width, int height) 
	{
		String logString = "";
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | 
				   GL10.GL_DEPTH_BUFFER_BIT);
		gl.glViewport(0, 0, width, height);
		((GL11) gl).glGetIntegerv(GL11.GL_VIEWPORT, Viewport, 0);
		for(int i = 0; i < Viewport.length; i++)
			logString += " " + Viewport[i] ;
		Log.i(TAG, " View port " +logString );
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		GLU.gluPerspective(gl, 45.0f, (float)width / (float) height, 
				.1f, 1000.0f);
		((GL11) gl).glGetFloatv(GL11.GL_PROJECTION_MATRIX, ProjectionView, 0);
		for(int i = 0; i < ProjectionView.length; i++)
			logString += " " + ProjectionView[i] ;
		Log.i(TAG, " ProjectionView " +logString );
		
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadIdentity();
		
		
	}
	
	 public void setTimer(Timer worldTimer)
	  {
		  timer = worldTimer;
	  }
	  

	public void onSurfaceCreated(GL10 gl, EGLConfig config) 
	{
		mGL = gl;
		
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | 
				   GL10.GL_DEPTH_BUFFER_BIT);
		gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		gl.glShadeModel(GL10.GL_FLAT);
		gl.glClearDepthf(1.0f);
		gl.glEnable(GL11.GL_DEPTH_TEST);
		gl.glDepthFunc(GL11.GL_LEQUAL);
		gl.glHint(GL10.GL_POINT_SMOOTH_HINT, GL10.GL_NICEST);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		gl.glEnable(GL10.GL_BLEND);   
		gl.glDisable(GL10.GL_LIGHTING);
		
		String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
		String version = gl.glGetString(GL10.GL_VERSION);
		String RenderType = gl.glGetString(GL10.GL_RENDERER);
		
		mIsOGL10 = version.contains("1.0");
		mIsSoftwareRender = RenderType.contains("PixelFinger");
		mSupportTexture = extensions.contains("draw_texture");
		
		mSupportVBO = !mIsSoftwareRender && (!mIsOGL10 || 
					extensions.contains("vertex_buffer_object"));
		
		
		
		Log.i(TAG, "GFX Support: "+ version + "(" + RenderType + "): "
				+ (mSupportTexture ? "Draw Textures " : " ") +
				(mSupportVBO ? "VBOs " :  " "));
		
	
		
		
		
		
	}
	
	
	public void reloadTextures()
	{
		for(Mesh M: root.mMeshList)
		{
			
			M.mShouldLoadTexture = true;
		}
	}
	protected void addMesh(Mesh mesh)
	{
		root.add(mesh);
	}
	
	
	public void setmTextView(TextView tv)
	{
		mText = tv;
	}
	
	
	public void clearScene()
	{
		for(Mesh M: root.mMeshList)
		{
			
			M.clearMesh(mGL);
		}
		root.clear();
		/*try {
			finalize();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		
	}
	
	public int getListSize()
	{
		return root.size();
		
	}
	
	
	
	public void updatePosition(float x, float y, float z)
	{
		mPosition[0] += x;
		mPosition[1] += y;
		mPosition[2]+= z;
		isDirty = true;
	}
	
	public void setPosition(float x, float y, float z)
	{
		mPosition[0] = x;
		mPosition[1] = y;
		mPosition[2] = z;
		isDirty = true;
	}
	

	public void updateRotation(float x, float y, float z)
	{
		mRotation[0] += x;
		mRotation[1] += y;
		mRotation[2] += z;
		isDirty = true;
	}
	
	public void setRotation(float x, float y, float z)
	{
		mRotation[0] = x;
		mRotation[1] = y;
		mRotation[2] = z;
		isDirty = true;
		
	}
	
	
	public float[] getPosition()
	{
		return mPosition;
	}
	
	public void updateFocus(float x, float y, float z)
	{
		
	}
	
	public void setFocus(float x, float y, float z)
	{
		
	}
	
	public void setFocus(float [] focus)
	{
		
		CameraFocus = focus;
		
	}
	public  void setUpVector(float x, float y, float z)
	{
		
	}
	
	public  void updateUpVector(float x, float y, float z)
	{
		
	}
	
	public void setDirty(boolean dirty)
	{
		isDirty = dirty;
	}
	
	public boolean getDirty()
	{
		return isDirty;
	}
	
	public short getTickCount()
	{
		return mTickCount;
	}
	
	public void resetTickCount()
	{
		mTickCount = 0;
	}
	
	public void activateOrbit()
	{
		orbitActivated = true;
	}
	
	
	public void increaseOrbit()
	{
		orbitIndex++;
		if(orbitIndex > 5)
		{
			orbitIndex = 0;
		}
		
		mPosition[0] = pointCoefX[orbitIndex] * cameraRadius;
		mPosition[2] = pointCoefZ[orbitIndex] * cameraRadius;
		Log.i(TAG, "Orbit Index: " + orbitIndex +  " mPosition[0] = " + mPosition[0] + " mPosition[2] = " + mPosition[2]);
		
	}
	public void decreaseOrbit()
	{
		orbitIndex--;
		if(orbitIndex < 0)
		{
			orbitIndex = 5;
		}
		
		mPosition[0] = pointCoefX[orbitIndex] * cameraRadius;
		mPosition[2] = pointCoefZ[orbitIndex] * cameraRadius;
		Log.i(TAG, "Orbit Index: " + orbitIndex +  " mPosition[0] = " + mPosition[0] + " mPosition[2] = " + mPosition[2]);
		
	}
	public void setView(View inView)
	{
		mView = inView;
		//Log.i(TAG, "View Data" + mView.toString());
	}
	
	

	 public boolean onTouchEvent(final MotionEvent event)
	  {
			
			/*
			GL11 gl11 = (GL11)mGL;
			float ModelView[] = new float[16];
			
			
			float meshCordsUpper[] = new float[4];
			float meshCordsLower[] = new float[4];
			String logString = "";
			
			
			
			
		
		
		
			Log.i(TAG, " Screen Dimensions " + Viewport[2] + " " + Viewport[3] );
			
			Log.i(TAG, "touch Data Raw X:" + event.getX() + " Raw Y: " + event.getY() );
			
			
//
//		   int temp = Viewport[2];
//		   Viewport[2] = Viewport[3];
//		   Viewport[3] = temp;
		                     
		
			
			//screenRatio = Viewport[2]/Viewport[3];
			
			
		
			FloatBuffer WinZbuff = FloatBuffer.allocate(1);
			
			
		
			(gl11).glReadPixels(  (int) event.getRawX(), (int)(event.getRawY()), 1, 1, GL11ExtensionPack.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, WinZbuff);
			
			Log.i(TAG, "WInZBUFF " + WinZbuff.get(0));
			float WinZ = WinZbuff.get(0);
		
			for(int index = 0; index< root.size(); index++)
			{
				if(root.get(index).isClickable)
				{
					Log.i(TAG, "current x:" +root.get(index).mTranslate[0]+ " y: " +root.get(index).mTranslate[1] + " y: " +root.get(index).mTranslate[2] );
					ModelView =root.get(index).getModelViewMatrix();
					assert ModelView != null;
					if(GLU.gluUnProject(event.getX(),
										event.getY() , 
										WinZ,
										ModelView, 0,
										ProjectionView, 0,
										Viewport, 0, 
										meshCordsLower, 0) == GL10.GL_FALSE)
						{
							Log.e(TAG, " ERROR project at z2");
						}
						logString = "";
						for(int i = 0; i < meshCordsLower.length; i++)
							logString += " " + meshCordsLower[i] ;
						Log.i(TAG, "screen cords at  "+ WinZ+ " " + logString  );
//			
//				if(GLU.gluUnProject(event.getX(),
//									Viewport[3] - event.getY() , 
//										-mPosition[2],
//										ModelView, 0,
//										ProjectionView, 0,
//										Viewport, 0, 
//										meshCordsUpper, 0) == GL10.GL_FALSE)
//				{
//					Log.e(TAG, " ERROR project at z2");
//				}
//				logString = "";
//				for(int i = 0; i < meshCordsUpper.length; i++)
//					logString += " " + meshCordsUpper[i] ;
//				Log.i(TAG, "screen cords at Z 0.0f: " + logString  );
				
				
						if(root.get(index).mTranslate[2] < meshCordsUpper[2] && root.get(index).mTranslate[2] >meshCordsLower[2])
						{
							
								Log.i(TAG, "Mesh is in Range");
								  root.get(index).isClicked =  !root.get(index).isClicked;
								  activeIndex = index;
						}
				}
					
				}	
		
			*/
			return true;
	}
	
		
	

	

}
